/**
 * 替换动作
 * @param {*} type 
 */
function sReplaceAction(type){

    /**
     * 修改元素集合
     */
    var elements = {};

    /**
     * 动作发生时的偏移量
     */
    var _offset = null;

    /**
     * 动作发生时的选项
     */
    var _opt = null;

    /**
     * 留痕状态
     */
    var _leaveTrace = false;

    /**
     * 获取动作类型
     */
    this.getActType = function(){
        return ssDict.sActionType.REPLACE;
    }

    /**
     * 设置留痕状态
     * @param {*} status true留痕 false不留痕
     */
    this.setLeaveTrace = function(status){
        _leaveTrace = status;
    }

    /**
     * 获取所有元素
     * @position 区域
     * @returns 
     */
    this.getElements = function(position){
        return position ? elements[position] : elements;
    }

    /**
     * 设置动作发生时偏移量
     * @param {*} offset 
     * @param {*} opt 
     */
    this.setOffset = function(offset, opt) {
        _offset = offset;
        _opt = opt;
    }

    /**
     * 替换文本元素内容
     * @param {*} element 文本元素
     * @param {*} replaceContent 替换内容
     * @param {*} offsets 元素偏移量集合
     * @param {*} position 页面区域
     * @param {*} opt 可选项
     */
    this.addText = function(element, replaceContent, offsets, position, opt){
        if(!_leaveTrace){
            addText.call(this, element, replaceContent, offsets, position);
        }else{
            addTextForLeaveTrace.call(this, element, replaceContent, offsets, position, opt);
        }
    }

    /**
     * 替换文本元素内容
     * @param {*} element 文本元素
     * @param {*} replaceContent 替换内容
     * @param {*} offsets 元素偏移量集合
     * @param {*} position 页面区域
     */
    var addText = function(element, replaceContent, offsets, position){
        var offset = null;
        var next = null;
        var innerText = "";
        var text = "";
        var rpc = "";
        var index = 0;
        var move = 0;

        for(var i in element.__texts){
            for(var j in element.__texts[i]){
                text = element.__texts[i][j];
                move = 0;

                for(var k = index; k < offsets.length; k++){
                    offset = offsets[k];
                    next = this.extractDeepOffset(offset);

                    if(next.pageIndex == parseInt(i) && next.rowIndex == parseInt(j)) {
                        rpc = offset.findStart ? replaceContent : "";
                        text = text.substring(0, next.start + 1 + move) 
                            + rpc + text.substring(next.end + 1 + move);
                        move += rpc.length - (next.end - next.start);
                    }else{
                        index = k;
                        break;
                    }
                }

                innerText += text;
            }
        }

        next = this.extractDeepOffset(offsets[0]);
        offsets[0].range = {
            start: next.start,
            end: next.end
        };

        var result = {
            element: element,
            oldContent: element.innerText,
            newContent: innerText,
            offset: offsets[0],
            position: position,
            mutate: true
        };

        element.innerText = innerText;

        if(!elements[position]){
            elements[position] = [];
        }

        elements[position].push(result);

        return this;
    }

    /**
     * 替换文本元素内容
     * @param {*} element 文本元素
     * @param {*} replaceContent 替换内容
     * @param {*} offsets 元素偏移量集合
     * @param {*} position 页面区域
     */
    var addTextForLeaveTrace = function(element, replaceContent, offsets, position, opt){
        opt = opt ? opt : {};

        var splitTexts = splitText.call(this, element, offsets);
        var text = null;
        var result = null;
        
        if(!elements[position]){
            elements[position] = [];
        }

        var next = this.extractDeepOffset(offsets[0]);

        if(next.pageIndex == opt.lastPageIndex && 
            next.rowIndex == opt.lastRowIndex && 
            opt.elementAddCount > 0){

            opt.lastElementIndex = next.elementIndex + opt.elementAddCount - 1;
        }else{
            opt.lastPageIndex = null;
            opt.lastRowIndex = null;
            opt.lastElementIndex = null;
        }

        var elementAddCount = 0;

        for(var i = 0; i < splitTexts.length; i++){
            text = splitTexts[i];
            text.newInText = replaceContent;

            if(i > 0){
                element = this.cloneData(element);

                delete element.delete;
                delete element.new;
                delete element.style.doubleDash;

                opt.mutateNew = true;
            }

            result = this.composeElements(text, element, text.offset, this.wrapElement, opt);

            if(result.leftElement){
                elements[position].push(result.leftElement);
                elementAddCount++;
            }
    
            if(result.inElement){
                result.inElement.element.delete = true;
                result.inElement.element.style.doubleDash = "middle";
                this.mergeOffsetNext(result.inElement.offset, {
                    range: {
                        start: result.inElement.element.innerText.length - 1,
                        end: result.inElement.element.innerText.length - 1
                    }
                });
                elements[position].push(result.inElement);
                elementAddCount++;
            }

            if(result.newInElement){
                result.newInElement.element.new = true;
                result.newInElement.element.style.doubleDash = "bottom";
                this.mergeOffsetNext(result.newInElement.offset, {
                    range: {
                        start: result.newInElement.element.innerText.length - 1,
                        end: result.newInElement.element.innerText.length - 1
                    }
                });
                elements[position].push(result.newInElement);
                elementAddCount++;
            }
    
            if(result.rightElement){
                this.mergeOffsetNext(result.rightElement.offset, {
                    range: {
                        start: result.rightElement.element.innerText.length - 1,
                        end: result.rightElement.element.innerText.length - 1
                    }
                });
                elements[position].push(result.rightElement);
                elementAddCount++;
            }
        }

        if(opt.elementAddCount == null){
            opt.elementAddCount = 0;
        }

        opt.elementAddCount += elementAddCount - 1;

        return this;
    }

    /**
     * 分隔文本
     * @param {*} element 
     * @param {*} offsets 
     */
    var splitText = function(element, offsets){
        var texts = element.__texts;
        var result = [];
        var last = null;

        for(var i in offsets){
            let offset = offsets[i];
            let next = this.extractDeepOffset(offset);
            
            let text = texts[offset.pageIndex][offset.rowIndex];
            let hasPrevText = false;

            if(last){
                if(next.pageIndex == last.next.pageIndex && next.rowIndex == last.next.rowIndex){
                    if(next.start > last.next.end){
                        result[result.length - 1].rightText = 
                            last.text.substring(last.next.end + 1, next.start + 1);
                    }
                    hasPrevText = true;
                }else if(last.next.end < last.text.length - 1){
                    result[result.length - 1].rightText = last.text.substring(last.next.end + 1);
                }
            }

            let splitText = {
                offset: offset
            };

            if(!hasPrevText && next.start > 0){
                splitText.leftText = text.substring(0, next.start + 1);
            }

            if(next.end > next.start){
                splitText.inText = text.substring(next.start + 1, next.end + 1);
            }

            result.push(splitText);

            last = {
                next: next,
                text: text
            };
        }

        if(last && last.next.end < last.text.length - 1){
            result[result.length - 1].rightText = last.text.substring(last.next.end + 1);
        }

        return result;
    }

    /**
     * 添加段落
     * @param {*} element 段落元素
     * @param {*} offsets 元素偏移量集合
     * @param {*} position 页面区域
     */
    this.addParagraph = function(element, offsets, position){
        var offset = this.deepCloneOffset(offsets[0]);

        var next = this.extractDeepOffset(offset);
        if(next.start == next.end){
            return;
        }

        elements[position] = elements[position]
            ? elements[position]
            : [];

        elements[position].push({
            position: position,
            element: element,
            offset: offset,
            delete: true
        });

        return this;
    }

    /**
     * 增加被替换掉的元素
     * @param {*} element 
     * @param {*} offset 
     * @param {*} position 
     * @param {*} opt
     * @returns 
     */
    this.addElement = function(element, offset, position, opt){
        opt = opt ? opt : {};

        offset = this.deepCloneOffset(offset);

        elements[position] = elements[position]
            ? elements[position]
            : [];

        var el = {
            position: position,
            element: element,
            offset: offset
        };

        if(opt.mutateNew){
            el.mutateNew = true;
        }else if(opt.delete){
            el.delete = true;
        }

        elements[position].push(el);

        return this;
    }

    /**
     * 返回当前动作的反向动作
     */
    this.reverse = function(){
        var results = [];

        for(var i in elements){
            var result = {
                type: i,
                elements: [],
                offset: null,
                insert: true
            };

            results.push(result);
    
            var el = null;
            var elc = null;

            for(var j in elements[i]){
                el = elements[i][j];
                elc = {...el};
    
                if(elc.oldContent != null){
                    elc.element.innerText = elc.oldContent;
                }
    
                if(elc.oldStyle != null){
                    elc.element.style = elc.oldStyle;
                }
    
                if(elc.element._sType != "sParagraph"){
                    if(elc.oldParagraphIndex != null){
                        el.newParagraphIndex = elc.element.__paragraphIndex;
                        elc.element.__paragraphIndex = elc.oldParagraphIndex;
                    }
                }else{
                    delete elc.element.__relFor;
                }
    
                if(!elc.offset.pageIndex){
                    var elRange = this.getElementPageRange(elc.element);
                    elc.offset = {
                        pageIndex: elRange.startPageIndex,
                        rowIndex: elRange.startRowIndex
                    };

                    if(el.element.innerText){
                        elc.offset.range = {
                            start: elc.element.innerText.length,
                            end: elc.element.innerText.length
                        }
                    }else{
                        elc.offset.range = {
                            start: 1,
                            end: 1
                        }
                    }
                }else{
                    elc.offset = this.deepCloneOffset(el.offset);
                    if(elc.offset.range){
                        elc.offset.range.start = el.offset.range.start;
                        elc.offset.range.end = el.offset.range.start;
                    }
                }
    
                if(!elc.delete && !result.offset){
                    result.offset = elc.offset;
                }
    
                result.elements.push(elc);
                
                this.clearMiddleProperties(elc);
            }
        }

        return results;
    }

    /**
     * 将反向动作恢复成正向动作
     */
    this.recover = function(){
        var results = [];

        for(var i in elements){
            var result = {
                type: i,
                elements: [],
                offset: null
            };
    
            results.push(result);

            var el = null;
            var elc = null;
            
            for(var j in elements[i]){
                el = elements[i][j];
                elc = {...el};
    
                if(elc.newContent != null){
                    elc.element.innerText = elc.newContent;
                }
    
                if(elc.newStyle != null){
                    elc.element.style = elc.newStyle;
                }
    
                if(elc.element._sType != "sParagraph"){
                    if(elc.newParagraphIndex != null){
                        elc.element.__paragraphIndex = elc.newParagraphIndex;
                    }
                }else{
                    delete elc.element.__relFor;
                }
    
                elc.offset = this.deepCloneOffset(el.offset);
    
                if(!elc.delete && !result.offset){
                    result.offset = elc.offset;
                }
    
                result.elements.push(elc);
    
                this.clearMiddleProperties(elc);
            }
        }

        return results;
    }
}